package com.gs.netty.client;

import com.gs.netty.client.remoting.WebSocketClient;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketClientProtocolHandler;
import lombok.Data;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantReadWriteLock;

@Data
public  class ChannelWrapper {

    private volatile boolean select;

    /**
     * 读写锁
     */
    private final ReentrantReadWriteLock lock;

    /**
     * 正常使用的 channel
     */
    private ChannelFuture channelFuture;

    /**
     * 要关闭的 channel
     */
    private ChannelFuture channelToClose;
    /**
     * 握手
     */
    private WebSocketClientHandshaker handshaker;
    /**
     * 最后响应时间
     */
    private long lastResponseTime;
    /**
     * 连接地址
     */
    private final WebSocketClient.WebSocketClientChannelInitializer channelInitializer;
    /**
     * 服务权重值
     */
    private volatile int weight;
    /**
     * 轮询权重的值
     */
    private final AtomicInteger current = new AtomicInteger(0);

    /**
     * 最后更新轮询权重时间
     */
    private long lastUpdate;


    public ChannelWrapper(WebSocketClient.WebSocketClientChannelInitializer channelInitializer, ChannelFuture channelFuture) {
        this.lock = new ReentrantReadWriteLock();
        this.channelFuture = channelFuture;
        this.handshaker =  channelFuture.channel().pipeline().get(WebSocketClientProtocolHandler.class).handshaker();
        this.lastResponseTime = System.currentTimeMillis();
        this.channelInitializer = channelInitializer;
        this.select=true;

    }

   public ChannelWrapper(WebSocketClient.WebSocketClientChannelInitializer channelInitializer) {
       this.lock = new ReentrantReadWriteLock();
       this.lastResponseTime = System.currentTimeMillis();
       this.channelInitializer = channelInitializer;
       this.select=false;
   }


    public boolean isAvailable(){
        return  getChannel() != null && getChannel().isActive();
    }

    public boolean isOK(){
        return  getChannel() != null && getChannel().isActive() && handshaker.isHandshakeComplete();
    }


    /**
     * 是否握手完成
     * @return
     */
    public boolean isHandshakeComplete(){
        return handshaker.isHandshakeComplete();
    }



    public Channel getChannel() {
        return getChannelFuture().channel();
    }

    public ChannelFuture getChannelFuture() {
        lock.readLock().lock();
        try {
            return this.channelFuture;
        } finally {
            lock.readLock().unlock();
        }
    }

    public void updateLastResponseTime() {
        this.lastResponseTime = System.currentTimeMillis();
    }

    public int getWeight() {
        return weight;
    }

    public void setLastUpdate(long lastUpdate) {
        this.lastUpdate = lastUpdate;
    }

    public long increaseCurrent() {
        // 加权值
        return current.addAndGet(weight);
    }

    public void sel(int total) {
        current.addAndGet(-1 * total);

    }

    /**
     * 重连
     * @param bootstrap
     * @return
     */
    public boolean reconnect(Bootstrap bootstrap) {
        if (!channelFuture.channel().isActive()) {
            if (lock.writeLock().tryLock()) {
                try {
                    if (!channelFuture.channel().isActive()) {
                        this.channelToClose = channelFuture;
                        this.channelFuture = bootstrap.handler(channelInitializer).connect(channelInitializer.getUri().getHost(), channelInitializer.getUri().getPort());
                        this.handshaker = channelFuture.channel().pipeline().get(WebSocketClientProtocolHandler.class).handshaker();
                        this.lastResponseTime = System.currentTimeMillis();
                        return true;
                    }
                } finally {
                    lock.writeLock().unlock();
                }
            }
        }
        return false;
    }

    public String getChannelAddress() {
        return channelInitializer.getUri().getPath();
    }
}